
#include <BPickHit>
#include "member_BPickHit.h"
#include "member_BShape.h"
#include "member_BObject.h"

using namespace BWE;

#define member					(*(member_BPickHit*)_ptr)
#define member_allocate()		_ptr = new member_BPickHit(this)
#define member_release()		delete (member_BPickHit*)_ptr

BPickHit::BPickHit()
{
	member_allocate();
}
BPickHit::BPickHit(const BString& name) : BObject(name)
{
	member_allocate();
}
BPickHit::BPickHit(BScene* scene)
{
	member_allocate();
	member.scene = scene;
}
BPickHit::BPickHit(BShape* shape)
{
	member_allocate();
	member.shape = shape;
}
BPickHit::BPickHit(BReal ratio)
{
	member_allocate();
	member.ratio = ratio;
}
BPickHit::BPickHit(const BPickHit& other) : BObject(other.name())
{
	member_allocate();
	this->copy(&other);
}
BPickHit::~BPickHit()
{
	member_release();
}

void BPickHit::copy(const BPickHit* other)
{
	object_member(this)->name = object_member(other)->name;
	member.scene = hit_member(other)->scene;
	member.group = hit_member(other)->group;
	member.node = hit_member(other)->node;
	member.shape = hit_member(other)->shape;
	member.element = hit_member(other)->element;
	member.index = hit_member(other)->index;
	member.primitive = hit_member(other)->primitive;
	member.ratio = hit_member(other)->ratio;
	member.point = hit_member(other)->point;
	member.normal = hit_member(other)->normal;
}
BPickHit* BPickHit::clone() const
{
	BPickHit* hit = new BPickHit();
	hit->copy(this);
	return hit;
}

void BPickHit::setScene(BScene* scene)
{
	if (member.scene != scene)
	{
		member.scene = scene;
	}
}
BScene* BPickHit::scene() const
{
	return member.scene;
}

void BPickHit::setGroup(BGroup* group)
{
	if (member.group != group)
	{
		member.group = group;
	}
}
BGroup* BPickHit::group() const
{
	return member.group;
}

void BPickHit::setNode(BNode* node)
{
	if (member.node != node)
	{
		member.node = node;
	}
}
BNode* BPickHit::node() const
{
	return member.node;
}

void BPickHit::setShape(BShape* shape)
{
	if (member.shape != shape)
	{
		member.shape = shape;
	}
}
BShape* BPickHit::shape() const
{
	return member.shape;
}

void BPickHit::setElement(BElement* element)
{
	if (member.element != element)
	{
		member.element = element;
	}
}
BElement* BPickHit::element() const
{
	return member.element;
}

void BPickHit::setPrimitive(Primitive primitive)
{
	member.primitive = primitive;
}
Primitive BPickHit::primitive() const
{
	return member.primitive;
}

void BPickHit::setIndex(int index)
{
	member.index = index;
}
int BPickHit::index() const
{
	return member.index;
}

void BPickHit::setRatio(BReal ratio)
{
	member.ratio = ratio;
}
BReal BPickHit::ratio() const
{
	return member.ratio;
}

void BPickHit::setPoint(const BVector& point)
{
	member.point = point;
}
const BVector& BPickHit::point() const
{
	return member.point;
}

void BPickHit::setNormal(const BVector& normal)
{
	member.normal = normal;
}
const BVector& BPickHit::normal() const
{
	return member.normal;
}

bool BPickHit::empty() const
{
	return !member.node && !member.shape;
}
BString BPickHit::path(const char* split) const
{
	BString str;
	BGroup* group = member.group;
	while (group)
	{
		if (str.size())
			str.prepend(split);
		str.prepend(group->name());
		group = group->parent();
	}
	if (member.node)
		str << split << member.node->name();
	if (member.shape)
		str << split << member.shape->name();
	return str;
}
BString BPickHit::path(const BString& split) const
{
	BString str;
	BGroup* group = member.group;
	while (group)
	{
		if (str.size())
			str.prepend(split);
		str.prepend(group->name());
		group = group->parent();
	}
	if (member.node)
		str << split << member.node->name();
	if (member.shape)
		str << split << member.shape->name();
	return str;
}

BMatrix BPickHit::absoluteMatrix() const
{
	BMatrix matrix;
	if (BShape* shape = member.shape)
	{
		matrix = shape->matrix();
		if (shape_member(shape)->isolate)
			return matrix;
	}
	if (member.node)
		matrix *= member.node->matrix();
	return matrix;
}
BVector BPickHit::absolutePoint() const
{
	BVector point = member.point;
	if (BShape* shape = member.shape)
	{
		point *= shape->matrix();
		if (shape_member(shape)->isolate)
			return point;
	}
	if (member.node)
		point *= member.node->matrix();
	return point;
}
BVector BPickHit::absoluteNormal() const
{
	BVector normal = member.normal;
	if (BShape* shape = member.shape)
	{
		normal *= shape->rotate();
		if (shape_member(shape)->isolate)
			return normal;
	}
	if (member.node)
	{
		normal *= member.node->rotate();
	}
	return normal;
}

